﻿using Admin2020.Core.Domain;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Admin2020.Data.Data
{
    public class EfRepository<T>:IRepository<T> where T : BaseEntity
    {
        private readonly Admin2020DbContext _context;
        private DbSet<T> _entities;


        public EfRepository(Admin2020DbContext context)
        {
            this._context = context;
        }

        public void Delete(T entity)
        {
            try
            {
                if (entity == null)
                    throw new ArgumentNullException(nameof(entity));

                Entities.Remove(entity);

                _context.SaveChanges();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public void Delete(IEnumerable<T> entities)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException(nameof(entities));

                foreach (var entity in entities)
                    Entities.Remove(entity);

                _context.SaveChanges();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public T GetById(object id)
        {
            return Entities.Find(id);
        }

        public void Insert(T entity)
        {
            try
            {
                if (entity == null)
                    throw new ArgumentNullException(nameof(entity));

                entity.IsActive = true;
                entity.IsDeleted = false;
                entity.CreatedTime = DateTime.Now;
                entity.UpdatedTime = DateTime.Now;
                entity.DisplayOrder = entity.DisplayOrder > 0 ? entity.DisplayOrder : 0;
                entity.Remarks = "";

                Entities.Add(entity);

                _context.SaveChanges();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public async Task InsertAsync(T entity)
        {
            try
            {
                if (entity == null)
                    throw new ArgumentNullException(nameof(entity));

                entity.IsActive = true;
                entity.IsDeleted = false;
                entity.CreatedTime = DateTime.Now;
                entity.UpdatedTime = DateTime.Now;
                entity.DisplayOrder = entity.DisplayOrder > 0 ? entity.DisplayOrder : 0;
                entity.Remarks = "";

                Entities.Add(entity);

                await _context.SaveChangesAsync();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public void Insert(IEnumerable<T> entities)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException(nameof(entities));

                foreach (var entity in entities)
                {
                    entity.IsActive = true;
                    entity.IsDeleted = false;
                    entity.CreatedTime = DateTime.Now;
                    entity.UpdatedTime = DateTime.Now;
                    entity.DisplayOrder = entity.DisplayOrder > 0 ? entity.DisplayOrder : 0;
                    Entities.Add(entity);
                }


                _context.SaveChanges();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public async Task InsertAsync(IEnumerable<T> entities)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException(nameof(entities));

                foreach (var entity in entities)
                {
                    entity.IsActive = true;
                    entity.IsDeleted = false;
                    entity.CreatedTime = DateTime.Now;
                    entity.UpdatedTime = DateTime.Now;
                    entity.DisplayOrder = entity.DisplayOrder > 0 ? entity.DisplayOrder : 0;
                    Entities.Add(entity);
                }


                await _context.SaveChangesAsync();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public void Update(T entity)
        {
            try
            {
                if (entity == null)
                    throw new ArgumentNullException(nameof(entity));

                entity.UpdatedTime = DateTime.Now;
                _context.SaveChanges();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public void Update(IEnumerable<T> entities)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException(nameof(entities));

                foreach (var entity in entities)
                {
                    entity.UpdatedTime = DateTime.Now;
                }

                _context.SaveChanges();
            }
            catch (Exception dbEx)
            {
                //ensure that the detailed error text is saved in the Log
                throw dbEx;
            }
        }

        public IQueryable<T> FromSqlInterpolated(FormattableString sql)
        {
            return this.Entities.FromSqlInterpolated(sql);
        }

        public IQueryable<T> FromSqlRaw(string sql, params object[] paramerers)
        {
            return this.Entities.FromSqlRaw(sql, paramerers);
        }

        #region 属性

        /// <summary>
        /// Gets a table
        /// </summary>
        public virtual IQueryable<T> Table
        {
            get
            {
                return Entities;
            }
        }

        /// <summary>
        /// Gets a table with "no tracking" enabled (EF feature) Use it only when you load record(s) only for read-only operations
        /// </summary>
        public virtual IQueryable<T> TableNoTracking
        {
            get
            {
                return Entities.AsNoTracking();
            }
        }

        /// <summary>
        /// Entities
        /// </summary>
        protected virtual DbSet<T> Entities
        {
            get
            {
                if (_entities == null)
                    _entities = _context.Set<T>();
                return _entities;
            }
        }

        #endregion
    }
}
